package cc.rengu.igas.opms.core.service.trans.quickpay;

import cc.rengu.igas.channel.ncqs.facade.response.NcqsAgreePaySignWithSmsAcqResponse;
import cc.rengu.igas.channel.ncqs.facade.result.Result;
import cc.rengu.igas.channel.nucc.facade.response.VerifySignResponse;
import cc.rengu.igas.opms.common.enums.RespCodeEnum;
import cc.rengu.igas.opms.core.service.base.ManageService;
import cc.rengu.igas.opms.facade.request.SignWithSmsRequest;
import cc.rengu.igas.opms.facade.response.SignWithSmsResponse;
import cc.rengu.igas.share.common.constant.ShareParamConstant;
import cc.rengu.igas.share.core.realize.UserService;
import cc.rengu.igas.share.core.realize.impl.UserServiceImpl;
import cc.rengu.oltp.service.base.ChannelBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.SignAcctInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.SignAcctInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.ChannelCallCfg;
import cc.rengu.oltp.service.common.entity.SignAcctInfo;
import cc.rengu.oltp.service.common.enums.CheckResultEnum;
import cc.rengu.oltp.service.common.enums.TransStatusEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.OrderInfo;
import cc.rengu.oltp.service.realize.ImageCodeService;
import cc.rengu.oltp.service.realize.TransCustomImpl;
import cc.rengu.oltp.service.realize.impl.ImageCodeServiceImpl;
import cc.rengu.oltp.utility.util.ConvertUtil;
import cc.rengu.oltp.utility.util.StringUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;


import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 银行卡签约触发短信服务
 * 银行卡签约时校验是否已完成签约,若已完成签约交易阻断
 * 更新签约手机号时校验必须存在签约关系
 * 银行卡重新签约的时候不校验是否存在签约关系
 * 签约类型根据报文头业务类型字段进行判断
 *
 * @author keyi
 * @modify by wangcheng
 * @date 2020/3/20.
 */
public class SignWithSmsService extends ManageService implements TransCustomImpl {
    @Override
    protected Object bizBeforeCust() throws Exception {
        SignWithSmsRequest signWithSmsRequest = new SignWithSmsRequest();
        ConvertUtil.convertOutput(signWithSmsRequest);
        //交易类型判断
        if (!"0".equals(signWithSmsRequest.getTransType()) &&
                !"1".equals(signWithSmsRequest.getTransType()) &&
                !"2".equals(signWithSmsRequest.getTransType())) {
            rglog.warn("不识别的交易类型，transType:<{}>", signWithSmsRequest.getTransType());
            throw new BizException(RespCodeEnum.PARAM_ERROR.getRespCode(), RespCodeEnum.PARAM_ERROR.getRespDesc());
        }
        //贷记卡必输字段判断
        if ("01".equals(signWithSmsRequest.getCardType()) || "11".equals(signWithSmsRequest.getCardType())) {
            if (StringUtil.isEmptyOrNull(signWithSmsRequest.getCvn2()) || StringUtil.isEmptyOrNull(signWithSmsRequest.getExprDate())) {
                rglog.warn("贷记卡签约时CVN2和卡有效期必输");
                throw new BizException(RespCodeEnum.PARAM_ERROR.getRespCode(), RespCodeEnum.PARAM_ERROR.getRespDesc());
            }
        }

        return signWithSmsRequest;
    }

    @Override
    protected BizResponse bizProcessCust(Object request) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        SignWithSmsRequest signWithSmsRequest = (SignWithSmsRequest) request;
        String instId = signWithSmsRequest.getHeader().getInstId();
        String platMchntNo = signWithSmsRequest.getPlatMchntNo();
        String userId = signWithSmsRequest.getUserId();
        String signTokenType = signWithSmsRequest.getSignTokenType();
        String certType = signWithSmsRequest.getCertType();
        String certNo = signWithSmsRequest.getCertNo();
        String signAcctNo = signWithSmsRequest.getAcctNo();

        UserService userService = new UserServiceImpl();
        String signInstId = userService.getUserSignInst();

        //校验图形验证码
        rglog.debug("开始校验图形验证码");
        ImageCodeService imageCodeService = new ImageCodeServiceImpl();
        boolean imageVerifyFlag = imageCodeService.verifyImageCode(instId, signWithSmsRequest.getImageAuthCodeSeqNum(), signWithSmsRequest.getImageAuthCode());
        if (!imageVerifyFlag) {
            rglog.warn("图片验证码校验失败!");
            throw new BizException(RespCodeEnum.VERIFICATION_CODE_INVALID.getRespCode(), RespCodeEnum.VERIFICATION_CODE_INVALID.getRespDesc());
        }

        //获取签约关系 区分用户是否登陆进行判断
        SignAcctInfoMapper signAcctInfoMapper = new SignAcctInfoMapperImpl();
        List<SignAcctInfo> signAcctInfos;
        if (StringUtil.isEmptyOrNull(userId)) {
            rglog.debug("未上传用户标识，开始检查是否签约。");
            signAcctInfos = signAcctInfoMapper.selectSignAcctInfoByCertInfo(instId, certType, certNo);
        } else {
            rglog.debug("已上传用户标识，开始检查是否签约。");
            signAcctInfos = signAcctInfoMapper.selectSignAcctInfoBySignTyUserId(instId, userId, signInstId);
            //校验当前用户证件号是否一致
            List<SignAcctInfo> collect = signAcctInfos.stream().filter(item -> certType.equals(item.getCertType())).collect(Collectors.toList());
            for (SignAcctInfo signAcctInfo : collect) {
                if (!signAcctInfo.getCertNo().equals(certNo)) {
                    rglog.warn("用户上传的证件号不一致，userId:<{}>,certType:<{}>,上传的证件号:<{}>,本地存放证件号:<{}>", userId, certType, certNo, signAcctInfos.get(0).getCertNo());
                    throw new BizException(RespCodeEnum.IDENTITY_INFORM_DISACCORD.getRespCode(), RespCodeEnum.IDENTITY_INFORM_DISACCORD.getRespDesc());
                }
            }
        }

        //根据签约关系进行判断
        if (null != signAcctInfos && !signAcctInfos.isEmpty()) {
            //获取已经存在的签约关系
            signAcctInfos = signAcctInfos.stream().filter(item -> AppParamConstant.YES.equals(item.getSignStatus())
                    && item.getSignAcctNo().endsWith(signAcctNo)).collect(Collectors.toList());
            //银行签约触发短信不能存在已签约的关系
            if ("0".equals(signWithSmsRequest.getTransType()) && !signAcctInfos.isEmpty()) {
                rglog.warn("用户已经完成签约，SIGN_TOKEN_TYPE:<{}> ,SIGN_INST:<{}>,CERT_NO:<{}> ,SIGN_ACCT_NO:<{}>", signTokenType, platMchntNo, certNo, signAcctNo);
                throw new BizException(RespCodeEnum.EXIT_SIGN_INFO_ERROR.getRespCode(), RespCodeEnum.EXIT_SIGN_INFO_ERROR.getRespDesc());
            } else if ("1".equals(signWithSmsRequest.getTransType())) {
                //银行卡重新签约不关注是否存在签约关系
                rglog.info("银行卡重新签约不关注是否存在签约信息,transType:<{}>", signWithSmsRequest.getTransType());
            } else if ((signAcctInfos.isEmpty()) && "2".equals(signWithSmsRequest.getTransType())) {
                //更换银行预留手机号
                rglog.warn("当前用户不存在签约关系,无法做更换银行预留手机号的交易");
                throw new BizException(RespCodeEnum.INVALID_SIGN.getRespCode(), RespCodeEnum.INVALID_SIGN.getRespDesc());
            }
        } else {
            //修改签约手机号的交易不存在签约关系，交易终止
            if ("2".equals(signWithSmsRequest.getTransType())) {
                rglog.warn("当前用户不存在签约关系,无法做更换银行预留手机号的交易");
                throw new BizException(RespCodeEnum.INVALID_SIGN.getRespCode(), RespCodeEnum.INVALID_SIGN.getRespDesc());
            }
        }

        //调用通道发送短信
        if (null == txnInfo.getChannelCallCfgList() || txnInfo.getChannelCallCfgList().isEmpty()) {
            rglog.error("<{}-{}>交易未配置交易通道服务调用配置信息！", txnInfo.getSrcTxnAuthCfg().getTxnNum(), txnInfo.getSrcTxnAuthCfg().getTxnName());
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }
        List<ChannelCallCfg> channelCallCfgList = txnInfo.getChannelCallCfgList().stream().filter(item ->
                item.getCallIndex().equals(ChannelBaseService.FIRST_CHANNEL_CALL_INDEX)).collect(Collectors.toList());
        ChannelCallCfg channelCallCfg = channelCallSceneDiscern(signWithSmsRequest, channelCallCfgList);
        Class channelClasz = Class.forName(channelCallCfg.getCallChannelImpl());
        ChannelBaseService channelBaseService = (ChannelBaseService) channelClasz.newInstance();
        channelBaseService.callService(txnInfo, null, channelCallCfg.getBizScene(), request);

        //应答信息
        SignWithSmsResponse signWithSmsResponse = new SignWithSmsResponse();
        signWithSmsResponse.setSmsVerifySeqNum(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM));
        signWithSmsResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        signWithSmsResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        BizResponse<SignWithSmsResponse> bizResponse = new BizResponse<>();
        bizResponse.setRspSysId(AppParamConstant.SYS_ID);
        bizResponse.setResult(signWithSmsResponse);
        bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        return bizResponse;
    }

    @Override
    protected void bizAfterCust(Object response) throws Exception {
        BizResponse bizResponse = (BizResponse) response;
        SignWithSmsResponse signWithSmsResponse = (SignWithSmsResponse) bizResponse.getResult();
        ConvertUtil.convertInput(signWithSmsResponse);
    }

    @Override
    public ChannelCallCfg channelCallSceneDiscern(Object request, List<ChannelCallCfg> channelCallCfgList) throws Exception {
        Optional<ChannelCallCfg> channelCallCfgOpt = channelCallCfgList.stream().filter(item ->
                item.getBizScene().equals(ShareParamConstant.CALL_CFG_DEFAULT_BIZ_SCENE)).findFirst();
        return channelCallCfgOpt.orElse(null);
    }

    @Override
    public CheckResultEnum channelCallPreCheck(Object request, ChannelCallCfg channelCallCfg, OrderInfo orderInfo) throws Exception {
        //网联协议支付签约身份认证，设置交易类别为0201
        SignWithSmsRequest signWithSmsRequest = (SignWithSmsRequest) request;
        if ("01".equals(signWithSmsRequest.getHeader().getBizType())) {
            XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
            xmlTreeUtil.setXmlTreeStringValue("trxCtgy", "0201");
        }
        return CheckResultEnum.PASSED;
    }

    @Override
    public TransStatusEnum channelCallResultProc(Object request, ChannelCallCfg channelCallCfg, TransStatusEnum transStatusEnum, Object channelResponse, OrderInfo needUpdateOrderInfo) throws Exception {
        if (null != channelResponse) {
            XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
            //将动态短信关联码/银联交易流水号 更新到非金融流水表中
            if ("00".equals(channelCallCfg.getBizScene())) {
                //银联无卡快捷发送短信场景
                Result<NcqsAgreePaySignWithSmsAcqResponse> callResult = (Result<NcqsAgreePaySignWithSmsAcqResponse>) channelResponse;
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.CHANNEL_SEQ_NUM, callResult.getResult().getChannelSeqNum());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.CHANNEL_ORDER_ID, callResult.getResult().getSmsKey());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.CHANNEL_RECON_KEY, callResult.getResult().getSettleKey());
            } else if ("01".equals(channelCallCfg.getBizScene())) {
                //网联协议支付发送短信场景
                cc.rengu.igas.channel.nucc.facade.result.Result<VerifySignResponse> callResult = (cc.rengu.igas.channel.nucc.facade.result.Result<VerifySignResponse>) channelResponse;
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.CHANNEL_SEQ_NUM, callResult.getResult().getAuthMsgId());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.CHANNEL_ORDER_ID, callResult.getResult().getAuthMsgId());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.CHANNEL_RECON_KEY, callResult.getResult().getAuthMsgId());
            }
        }
        return transStatusEnum;
    }
}
